#include "qdebug.h"
#include "qdatetime.h"
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

QString w;
QString f;
QString l;
QString n;
uint32_t waitTime = 3;
bool info = false;

void forkChildProcess(int)
{
    int status = 0;
    // 等待子进程中断或终止，释放子进程资源
    // 否则死掉的子进程会变成僵尸进程

    //有多个子进程的情况
//    pid_t pid;
//    /* 由于该信号不能叠加，所以可能同时有多个子进程已经结束 所以循环wait */
//    while((pid = waitpid(0, &status, WNOHANG)) > 0){
//        if (WIFEXITED(status))    // 判断子进程的退出状态 是否是正常退出
//            printf("-----child %d exit with %d\n", pid, WEXITSTATUS(status));
//        else if (WIFSIGNALED(status))   // 判断子进程是否是 通过信号退出
//            printf("child %d killed by the %dth signal\n", pid, WTERMSIG(status));
//    }

    int pid = wait(&status);
    if (pid < 0)
    {
        qDebug() << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss : Error :").toUtf8().data();
        printf("forkChildProcess error: %s\n", strerror(errno));
        return;
    }

    if(info)
    {
        qDebug() << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss : 等待").toUtf8().data() << QString::number(waitTime).toUtf8().data() << "秒";
    }
    // 等待重新启动子进程
    if(waitTime > 0)
    {
         sleep(waitTime);
    }
    if(info)
    {
        qDebug() << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss : 等待完成").toUtf8().data();
    }

    pid = fork();
    if (pid == 0)
    {
        if(info)
        {
            qDebug() << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss :").toUtf8().data() << "Restart->" + w + "; n = " + n + "; l = " + l + ";";
        }
        execl(w.toStdString().c_str(),n.toStdString().c_str(),l.toStdString().c_str(),NULL);
    }
}

int main(int argc, char *argv[])
{
    w = "";
    f = "";
    l = "";
    n = "";
    for(int i = 0;i < argc;i++)
    {
        QString cmd = argv[i];
        if(cmd.startsWith("-w"))    //需要守护的线程
        {
            cmd.remove(0,2);
            w = cmd;
        }
        else if(cmd.startsWith("-f"))   //第一次启动时需要传递的参数argv[1]
        {
            cmd.remove(0,2);
            f = cmd;
        }
        else if(cmd.startsWith("-l"))   //出错后重启时需要传递的参数argv[1]
        {
            cmd.remove(0,2);
            l = cmd;
        }
        else if(cmd.startsWith("-n"))   //argv[0]
        {
            cmd.remove(0,2);
            n = cmd;
        }
        else if(cmd.startsWith("-t"))   //等待时间
        {
            cmd.remove(0,2);
            waitTime = cmd.toUInt();
        }
        else if(cmd.startsWith("-i"))   //是否输出信息
        {
            cmd.remove(0,2);
            info = cmd.toUInt() == 1 ? true : false;
        }
        else if(cmd.startsWith("-h"))   //是否输出信息
        {

            qDebug() << "注意:以下所有参数 -xx与参数之间不加空格!";
            qDebug() << "-w 指定目标程序 绝对路径,";
            qDebug() << "-f 第一次启动时需要传递给目标程序的参数 :argv[1]";
            qDebug() << "-l 出错后重启时需要传递给目标程序的参数 :argv[1]";
            qDebug() << "-n 每次都会传递给目标程序的参数 :argv[0]";
            qDebug() << "-t 出错后重启时需要等待的时间(秒),默认值为3";
            qDebug() << "-i 是否输出信息";
            return 0;
        }
    }
    if(w == "")
    {
         qDebug() << "请使用-w指定目标程序";
         return -1;
    }
    // 初始化看门狗进程
    int pid = fork();
    if (pid)
    {
        while(true)
        {
            // 父进程一直监视子进程的运行状态
            // 捕获子进程结束信号
            assert(signal(SIGCHLD, forkChildProcess) != SIG_ERR);
            // 父进程挂起，当有信号来时被唤醒
            pause();
        }

    }
    // 运行子进程代码
    if(info)
    {
        qDebug() << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss :").toUtf8().data() << "Start->" + w + " n = " + n + "; f = " + f + ";";
    }
    execl(w.toStdString().c_str(),n.toStdString().c_str(),f.toStdString().c_str(),NULL);
    return 0;
}
